{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import asyncio\n",
    "import os\n",
    "import asyncio\n",
    "\n",
    "from typing import Annotated\n",
    "from openai import AsyncOpenAI\n",
    "\n",
    "\n",
    "from semantic_kernel.kernel import Kernel\n",
    "from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
    "from semantic_kernel.agents import ChatCompletionAgent, AgentGroupChat\n",
    "from semantic_kernel.agents.strategies import (\n",
    "    KernelFunctionSelectionStrategy,\n",
    "    KernelFunctionTerminationStrategy,\n",
    ")\n",
    "\n",
    "from semantic_kernel.functions import KernelFunctionFromPrompt\n",
    "\n",
    "from semantic_kernel.agents.open_ai import OpenAIAssistantAgent\n",
    "from semantic_kernel.contents import AuthorRole, ChatMessageContent\n",
    "from semantic_kernel.functions import kernel_function\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def _create_kernel_with_chat_completion(service_id: str) -> Kernel:\n",
    "    kernel = Kernel()\n",
    "    service_id=\"agent\"\n",
    "\n",
    "    client = AsyncOpenAI(\n",
    "    api_key=os.environ[\"GITHUB_TOKEN\"], base_url=\"https://models.inference.ai.azure.com/\")\n",
    "    kernel.add_service(\n",
    "        OpenAIChatCompletion(\n",
    "            ai_model_id=\"gpt-4o-mini\",\n",
    "            async_client=client,\n",
    "            service_id=service_id\n",
    "        )\n",
    "    )\n",
    "\n",
    "    return kernel\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# User: 'i would like to go to Paris.'\n",
      "# Agent - FrontDesk: 'Visit the Eiffel Tower for breathtaking views of the city.'\n",
      "# Agent - Concierge: 'While the Eiffel Tower is undeniably iconic, it tends to attract a large number of tourists, which diminishes the authenticity of the experience. To refine this recommendation, consider suggesting less famous vantage points that offer stunning views without the crowds, or perhaps recommend exploring local neighborhoods where travelers can immerse themselves in the daily life and culture of Parisians. That way, the experience will feel more genuine and local.'\n",
      "# IS COMPLETE: True\n"
     ]
    }
   ],
   "source": [
    "async def main():\n",
    "    REVIEWER_NAME = \"Concierge\"\n",
    "    REVIEWER_INSTRUCTIONS = \"\"\"\n",
    "    You are an are hotel concierge who has opinions about providing the most local and authetic experiences for travelers.\n",
    "    The goal is to determine if the front desk travel agent has reccommended the best non-touristy experience for a travler.\n",
    "    If so, state that it is approved.\n",
    "    If not, provide insight on how to refine the recommendation without using a specific example. \n",
    "    \"\"\"\n",
    "    agent_reviewer = ChatCompletionAgent(\n",
    "        service_id=\"concierge\",\n",
    "        kernel=_create_kernel_with_chat_completion(\"concierge\"),\n",
    "        name=REVIEWER_NAME,\n",
    "        instructions=REVIEWER_INSTRUCTIONS,\n",
    "    )\n",
    "\n",
    "    FRONTDESK_NAME = \"FrontDesk\"\n",
    "    FRONTDESK_INSTRUCTIONS = \"\"\"\n",
    "    You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers.\n",
    "    The goal is to provide the best activites and locations for a traveler to visit.\n",
    "    Only provide a single recomendation per response.\n",
    "    You're laser focused on the goal at hand.\n",
    "    Don't waste time with chit chat.\n",
    "    Consider suggestions when refining an idea.\n",
    "    \"\"\"\n",
    "    agent_writer = ChatCompletionAgent(\n",
    "        service_id=\"frontdesk\",\n",
    "        kernel=_create_kernel_with_chat_completion(\"frontdesk\"),\n",
    "        name=FRONTDESK_NAME,\n",
    "        instructions=FRONTDESK_INSTRUCTIONS,\n",
    "    )\n",
    "\n",
    "    termination_function = KernelFunctionFromPrompt(\n",
    "        function_name=\"termination\",\n",
    "        prompt=\"\"\"\n",
    "        Determine if the reccomendation is good.  If so, respond with a single word: yes\n",
    "\n",
    "        History:\n",
    "        {{$history}}\n",
    "        \"\"\",\n",
    "    )\n",
    "\n",
    "    selection_function = KernelFunctionFromPrompt(\n",
    "        function_name=\"selection\",\n",
    "        prompt=f\"\"\"\n",
    "        Determine which participant takes the next turn in a conversation based on the the most recent participant.\n",
    "        State only the name of the participant to take the next turn.\n",
    "        No participant should take more than one turn in a row.\n",
    "        \n",
    "        Choose only from these participants:\n",
    "        - {REVIEWER_NAME}\n",
    "        - {FRONTDESK_NAME}\n",
    "        \n",
    "        Always follow these rules when selecting the next participant, each conversation should be at least 4 turns:\n",
    "        - After user input, it is {FRONTDESK_NAME}'s turn.\n",
    "        - After {FRONTDESK_NAME} replies, it is {REVIEWER_NAME}'s turn.\n",
    "        - After {REVIEWER_NAME} provides feedback, it is {FRONTDESK_NAME}'s turn.\n",
    "\n",
    "        History:\n",
    "        {{{{$history}}}}\n",
    "        \"\"\",\n",
    "    )\n",
    "\n",
    "    chat = AgentGroupChat(\n",
    "        agents=[agent_writer, agent_reviewer],\n",
    "        termination_strategy=KernelFunctionTerminationStrategy(\n",
    "            agents=[agent_reviewer],\n",
    "            function=termination_function,\n",
    "            kernel=_create_kernel_with_chat_completion(\"termination\"),\n",
    "            result_parser=lambda result: str(result.value[0]).lower() == \"yes\",\n",
    "            history_variable_name=\"history\",\n",
    "            maximum_iterations=10,\n",
    "        ),\n",
    "        selection_strategy=KernelFunctionSelectionStrategy(\n",
    "            function=selection_function,\n",
    "            kernel=_create_kernel_with_chat_completion(\"selection\"),\n",
    "            result_parser=lambda result: str(\n",
    "                result.value[0]) if result.value is not None else FRONTDESK_NAME,\n",
    "            agent_variable_name=\"agents\",\n",
    "            history_variable_name=\"history\",\n",
    "        ),\n",
    "    )\n",
    "\n",
    "    input = \"i would like to go to Paris.\"\n",
    "\n",
    "    await chat.add_chat_message(ChatMessageContent(role=AuthorRole.USER, content=input))\n",
    "    print(f\"# User: '{input}'\")\n",
    "\n",
    "    async for content in chat.invoke():\n",
    "        print(f\"# Agent - {content.name or '*'}: '{content.content}'\")\n",
    "\n",
    "    print(f\"# IS COMPLETE: {chat.is_complete}\")\n",
    "\n",
    "await main()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
